package org.example.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.example.mapper.StockMapper;
import org.example.polo.Stock;
import org.example.service.i.IStockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;

@Service()
//@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
public class StockMysqlService implements IStockService {

    @Autowired
    StockMapper stockMapper;

    private ReentrantLock lock = new ReentrantLock();

    //    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    //@Transactional()
    public String deduct() {
        return deductLock();
//        return deductSyn();
    }

    private String deductLock() {
        lock.lock();
        int count = -1;
        try {
            count = deductCount();
        } finally {
            lock.unlock();
        }
        return "deduct success current stock " + count;
    }

    private synchronized String deductSyn() {
        int count = deductCount();
        return "deduct success current stock " + count;
    }

    private int deductCount() {
        int updateCount = -1;
        int count = -1;
//        deduct2Mybatic();
//        updateCount = deduct2MysqlUpdate();
//        deduct2MysqlSelectUpdate();
        deduct2Cas();
        return updateCount;
    }

    private void deduct2Cas() {
        int count;
        List<Stock> stocks = stockMapper.selectList(new QueryWrapper<Stock>().eq("product_code", 1001));
        Stock stock = stocks.get(0);
        if (Objects.nonNull(stock) && stock.getCount() > 0) {
            count = stock.getCount() - 1;
            int version = stock.getVersion();
            stock.setCount(count);
            stock.setVersion(version + 1);
            int update = stockMapper.update(stock, new UpdateWrapper<Stock>().eq("id", stock.getId()).eq("version", version));
            if (update == 0){
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                deduct2Cas();
            }
        }
    }

    private void deduct2Mybatic() {
        int count;
        Stock stock = stockMapper.selectOne(new QueryWrapper<Stock>().eq("product_code", 1001));
        if (Objects.nonNull(stock) && stock.getCount() > 0) {
            count = stock.getCount() - 1;
            stock.setCount(count);
            stockMapper.updateById(stock);
        }
    }

    private void deduct2MysqlSelectUpdate() {
        int count;
        List<Stock> stocks = stockMapper.selectUpdate("1001");
        Stock stock = stocks.get(0);
        if (Objects.nonNull(stock) && stock.getCount() > 0) {
            count = stock.getCount() - 1;
            stock.setCount(count);
            stockMapper.updateById(stock);
        }
    }

    private int deduct2MysqlUpdate() {
        int updateCount;
        updateCount = stockMapper.updateStocks("1001", 1);
        return updateCount;
    }

    //
    public String clear() {

        Stock stock = stockMapper.selectOne(new QueryWrapper<Stock>().eq("id", 1));
        stock.setCount(Stock.INIT);
        stockMapper.updateById(stock);
        int count = -1;
        stock = stockMapper.selectOne(new QueryWrapper<Stock>().eq("id", 1));
        count = stock.getCount();
        return "clear success ,current stock is " + count;
    }


}
